﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Audio;

using HadronData;

using Hadron.SpecialEffects;

namespace Hadron.Entities
{
    class Gate
        : LandEntity
    {
        private bool m_bTopAnchor, m_bOpen, m_bTimed;
        private float m_fTotalHeight, m_fTimer;
        private Polygon m_polygonGeometryLocal, m_polygonGeometryWorld;
        private Color m_colourField;
        private SoundEffectInstance m_soundEffectInstanceGate;

        public Gate(EntityMarker p_entityMarker, Environment p_environment, bool p_bTimed)
            : base(p_entityMarker, p_environment)
        {
            m_bOpen = false;
            m_bTopAnchor = false;
            m_bTimed = p_bTimed;
            m_nHealth = int.MaxValue;

            m_polygonGeometryLocal = new Polygon();
            m_polygonGeometryLocal.Edges.Add(new Edge(-8.0f,  0.0f, -6.0f, -6.0f, Color.Gray));
            m_polygonGeometryLocal.Edges.Add(new Edge( 8.0f,  0.0f,  6.0f, -6.0f, Color.Gray));
            m_polygonGeometryLocal.Edges.Add(new Edge(-6.0f, -6.0f,  6.0f, -6.0f, Color.Gray));

            // top - to relocate
            m_polygonGeometryLocal.Edges.Add(new Edge(-8.0f,  0.0f, -6.0f,  6.0f, Color.Gray));
            m_polygonGeometryLocal.Edges.Add(new Edge( 8.0f,  0.0f,  6.0f,  6.0f, Color.Gray));
            m_polygonGeometryLocal.Edges.Add(new Edge(-6.0f,  6.0f,  6.0f,  6.0f, Color.Gray));

            m_colourField = m_bTimed ? new Color(255, 128, 0) : Color.YellowGreen;
            for (int nIndex = 0; nIndex < 10; nIndex++)
                m_polygonGeometryLocal.Edges.Add(new Edge(m_colourField));

            m_polygonGeometryWorld = new Polygon(m_polygonGeometryLocal);

            m_soundEffectInstanceGate = AssetManager.Sounds.Gate.Play(0.0f, 0.0f, 0.0f, true);
        }

        public override void Update(GameTime p_gameTime)
        {
            if (m_edgeAnchor == null)
            {
                m_entityStatus = EntityStatus.Deactivated;
                return;
            }

            // anchor top part of gate
            if (!m_bTopAnchor)
            {
                HadronData.Ray ray = new HadronData.Ray(Vector2.UnitY * -5.0f, -Vector2.UnitY).TransformCopy(m_trnPlacement);

                Vector2 vecIntersectionPoint = Vector2.Zero;
                if (!m_environment.CurrentLevel.Intersects(ray, ref vecIntersectionPoint))
                {
                    m_entityStatus = EntityStatus.Deactivated;
                    return;
                }

                // fix geometry (upper gate node)
                m_fTotalHeight = (vecIntersectionPoint - Position).Length();
                Vector2 vecHeightOffset = new Vector2(0.0f, -m_fTotalHeight);
                for (int nIndex = 3; nIndex < 6; nIndex++)
                {
                    m_polygonGeometryLocal.Edges[nIndex].Start += vecHeightOffset;
                    m_polygonGeometryLocal.Edges[nIndex].End += vecHeightOffset;
                }

                // fix force field geometry
                float fGateHeight = m_fTotalHeight - 14.0f;
                for (int nIndex = 6; nIndex < 16; nIndex++)
                {
                    Vector2 vecPosition1 = new Vector2(0.0f, -7.0f - fGateHeight * (nIndex - 6) / 10.0f);
                    Vector2 vecPosition2 = new Vector2(0.0f, -7.0f - fGateHeight * (nIndex - 5) / 10.0f);
                    m_polygonGeometryLocal.Edges[nIndex].Start = vecPosition1;
                    m_polygonGeometryLocal.Edges[nIndex].End = vecPosition2;
                }

                m_bTopAnchor = true;

                m_circleBounds = m_polygonGeometryLocal.GetBoundingCircle(Position);
            }

            base.Update(p_gameTime);

            m_circleBounds.Centre = m_trnPlacement.Translation;

            m_nHealth = int.MaxValue;

            m_polygonGeometryWorld.Transform(m_trnPlacement, m_polygonGeometryLocal);

            if (m_bTimed)
            {
                float fDeltaTime = (float)p_gameTime.ElapsedGameTime.TotalSeconds;
                m_fTimer -= fDeltaTime;
                if (m_fTimer <= 0.0f)
                {
                    Open = !m_bOpen;
                    m_fTimer += 2.0f + (float)s_random.NextDouble() * 0.5f;
                }
            }

            if (m_bOpen)
            {
                // hide energy edges
                for (int nIndex = 6; nIndex < 16; nIndex++)
                {
                    m_polygonGeometryWorld.Edges[nIndex].Start
                        = m_polygonGeometryWorld.Edges[nIndex].End
                            = Position;
                }
            }
            else
            {
                // closed - oscillate force field edges
                for (int nIndex = 6; nIndex < 15; nIndex++)
                {
                    Vector2 vecEnd = m_polygonGeometryWorld.Edges[nIndex].End;
                    vecEnd.X += ((float)s_random.NextDouble() - 0.5f) * 12.0f;
                    vecEnd.Y += ((float)s_random.NextDouble() - 0.5f) * 12.0f;
                    m_polygonGeometryWorld.Edges[nIndex].End = vecEnd;
                    m_polygonGeometryWorld.Edges[nIndex + 1].Start = vecEnd;
                }

                // update sound volume
                m_soundEffectInstanceGate.Volume = m_environment.ComputeSoundVolume(Position);
            }
        }

        public override void Draw(SpriteBatch p_spriteBatch)
        {
            m_polygonGeometryWorld.Draw(p_spriteBatch);
        }

        public override void OnDeactivate()
        {
            if (m_soundEffectInstanceGate != null)
                m_soundEffectInstanceGate.Stop();
        }

        public override EntityType Type
        {
            get { return m_bTimed ? EntityType.TimedGate : EntityType.SwitchGate; }
        }

        public override bool Hostile
        {
            get { return !m_bOpen; }
        }

        public override bool Destructuble
        {
            get { return false; }
        }

        public override Geometry Geometry
        {
            get { return m_polygonGeometryWorld; }
        }

        public bool Open
        {
            get { return m_bOpen; }
            set
            {
                if (m_bOpen == value)
                    return;

                m_bOpen = value;

                // sound
                if (m_bOpen)
                    m_soundEffectInstanceGate.Stop();
                else
                    m_soundEffectInstanceGate.Play();

                // spawn two blasts
                Vector2 vecParticleVelocity
                    = m_trnPlacement.RotationComponent.Apply(Vector2.UnitY * -32.0f);
                ProjectileBlast projectileBlast = new ProjectileBlast(m_environment,
                    m_trnPlacement.Apply(Vector2.UnitY * -6.0f), m_colourField);
                projectileBlast.ParticleSystem.EmissionVelocity = vecParticleVelocity;
                projectileBlast.ParticleSystem.EmissionVelocityVariance = 32.0f;
                m_environment.SpecialEffects.Add(projectileBlast);

                projectileBlast = new ProjectileBlast(m_environment,
                    m_trnPlacement.Apply(Vector2.UnitY * (-m_fTotalHeight + 6.0f)), m_colourField);
                projectileBlast.ParticleSystem.EmissionVelocity = -vecParticleVelocity;
                projectileBlast.ParticleSystem.EmissionVelocityVariance = 32.0f;
                m_environment.SpecialEffects.Add(projectileBlast);
            }
        }

        public bool Timed
        {
            get { return m_bTimed; }
        }
    }
}
